/******************************************************************
 * Created by: DO HOANG HAI                                       
 * Date of Creation: 10/Oct/2007                                               
 * Date of last modification: 22/02/2008
 *                                                                
 * Description: Provide means to control network communication 
 * of the program
 * 
 * Status: Optimized and Finished
 ******************************************************************/
using System;
using System.Collections.Generic;
using System.Text;
using System.Net;
using System.Net.Sockets;


namespace Pbdms.BusinessLogic.Network
{
    /// <summary>
    /// a NetworkController object controls all the interactions with the network 
    /// and handles events from networkDealer module (data received from the network
    /// but can't be processed by this module will be passed to this NetworkController object)
    /// 
    /// </summary>
    public class NetworkController
    {
        /// <summary>
        /// Maximum hops for the request to be sent around the network
        /// </summary>
        public const int MAX_HOPS = 5;

        /// <summary>
        /// a Detwork Dealer component attached to the object to provide networking services
        /// </summary>
        NetworkDealer.NetworkDealer ntwkDealer = new NetworkDealer.NetworkDealer();

        /// <summary>
        /// a reference to the method which process the search results received from the network
        /// </summary>
        public SearchResultReceiver processSearchResultReceived;
        public BrowseResultBuddyReceiver processBuddyResultReceived;
        
        /// <summary>
        /// a delegate that defines SearchResultReceived event handler
        /// </summary>
        /// <param name="o1"></param>
        /// <param name="o2"></param>
        public delegate void SearchResultReceiver(object sender, Pbdms.NetworkDealer.EventArgs.SearchResultReceivedEventArgs e);
        
        public delegate void BrowseResultBuddyReceiver(object sender, Pbdms.NetworkDealer.EventArgs.BrowseResultBuddyReceivedEventArgs e);
                
        /// <summary>
        /// send a search request to the network
        /// </summary>
        /// <param name="searchObj"></param>
        /// <param name="processSearchResultReceived"></param>
        public void sendSearchRequest(Common.DataObject.SearchObj searchObj, SearchResultReceiver processSearchResultReceived)
        {
            this.processSearchResultReceived = processSearchResultReceived;
            
            ntwkDealer.sendSearchRequest(searchObj,DataController.BuddyController.create().getListOfBuddies());
            //wait for 7 seconds for the result from the network
            System.Threading.Thread.CurrentThread.Join(7000);
        }

        /// <summary>
        /// send a download request to thet network
        /// </summary>
        /// <param name="itemId"></param>
        /// <param name="ipAddTarget"></param>
        public void sendDownloadRequest(string itemId,string ipAddTarget, String file1, String file2)
        {
            ntwkDealer.sendDownloadRequest(itemId, IPAddress.Parse(ipAddTarget),file1, file2);
        }

        public void sendBrowseRequest(String strIpAdd, SearchResultReceiver processSearchResultReceived, BrowseResultBuddyReceiver processBrowseResultBuddyReceived)
        {
            IPAddress ipAdd = IPAddress.Parse(strIpAdd);
            this.processSearchResultReceived = processSearchResultReceived;
            this.processBuddyResultReceived = processBrowseResultBuddyReceived;
            ntwkDealer.sendBrowseRequest(ipAdd);
            //wait for 6 seconds for the result from the network
            System.Threading.Thread.CurrentThread.Join(6000);
        }

        /// <summary>
        /// Cnstructor
        /// </summary>
        public NetworkController()
        {            
            ntwkDealer.DownloadRequestReceived += new Pbdms.NetworkDealer.NetworkDealer.DownloadRequestReceivedEventHandler(ntwkDealer_DownloadRequestReceived);
            ntwkDealer.SearchRequestReceived +=new Pbdms.NetworkDealer.NetworkDealer.SearchRequestReceivedEventHandler(ntwkDealer_SearchRequestReceived); 
            ntwkDealer.searchResultReceived +=new Pbdms.NetworkDealer.NetworkDealer.SearchResultReceivedEventHandler(ntwkDealer_searchResultReceived);
            ntwkDealer.downloadClientReady += new Pbdms.NetworkDealer.NetworkDealer.DownloadClientReadyEventHandler(ntwkDealer_downloadClientReady);
            ntwkDealer.browseResultBuddyReceived += new Pbdms.NetworkDealer.NetworkDealer.BrowseResultBuddyReceivedEventHandler(ntwkDealer_browseResultBuddyReceived);
            ntwkDealer.browseRequestReceived += new Pbdms.NetworkDealer.NetworkDealer.BrowseRequestReceivedEventHandler(ntwkDealer_browseRequestReceived);
        }

        

        /// <summary>
        /// handler of DownloadClientReady event, triggered from Network Dealer component
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void ntwkDealer_downloadClientReady(object sender, Pbdms.NetworkDealer.EventArgs.DownloadClientReadyEventArgs e)
        {
            Common.DataObject.FileInfo fileInfoObj = DataController.FileInfoController.create().getFileInfoFromDB(e.RequestedItemId.ToString());
            if (fileInfoObj.FileName.Equals(e.FileName))
            {
                string filePath = fileInfoObj.Location + "\\" + fileInfoObj.FileName;

                if (System.IO.File.Exists(filePath))
                {
                    ntwkDealer.sendFile(e.ClientIpAdd, e.ClientPort, filePath);
                }
            }
            else
            {
                Common.DataObject.Comment commentObj = DataController.CommentController.create().getCommentFromDB(e.RequestedItemId.ToString());
                string filePath = commentObj.ReviewFile;
                if (System.IO.File.Exists(filePath))
                {
                    ntwkDealer.sendFile(e.ClientIpAdd, e.ClientPort, filePath);
                }
            }
                        
        }

        /// <summary>
        /// handler of the SearchResultReceived event triggered from network dealer component
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void ntwkDealer_searchResultReceived(object sender, Pbdms.NetworkDealer.EventArgs.SearchResultReceivedEventArgs e)
        {
            //pass the result back to the method which has been assigned to handle the result            
            processSearchResultReceived(sender, e);
            
        }

        /// <summary>
        /// handler of the SearchRequestReceived event triggered from network dealer component
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void ntwkDealer_SearchRequestReceived(object sender, Pbdms.NetworkDealer.EventArgs.SearchRequestReceivedEventArgs e)
        {
            //forward the message
            if (e.SearchRequestObj.curHop <= MAX_HOPS)
            {
                System.Collections.ArrayList arlBuddies = DataController.BuddyController.create().getListOfBuddies();
                if (arlBuddies != null && arlBuddies.Count > 0)
                {
                    foreach (Common.DataObject.Buddy bdd in arlBuddies)
                    {
                        if (!bdd.IpAdd.Equals(e.SearchRequestObj.ipAddSource.ToString()))
                            if ((e.SearchRequestObj.ipAddForwarder == null
                                || (e.SearchRequestObj.ipAddForwarder != null && !bdd.IpAdd.Equals(e.SearchRequestObj.ipAddForwarder.ToString()))
                                )&& !bdd.IpAdd.Equals(NetworkDealer.NetworkDealer.ipAddMyComputer.ToString()) )
                                ntwkDealer.forwardSearchRequest(e.SearchRequestObj, IPAddress.Parse(bdd.IpAdd));
                    }
                }
            }
            
            //perform searching and get result
            Common.DataObject.SearchObj searchObj = e.SearchRequestObj.searchObj;
            searchObj.SearchSource = Common.DataObject.SearchObj.SOURCE_LOCAL_ONLY;
            System.Collections.ArrayList arlResult =  Search.SearchProcessor.create(searchObj, false, this).getResult();
            //send the result
            if (arlResult != null && arlResult.Count > 0)
            {
                foreach (Common.DataObject.ResultItem resItem in arlResult)
                {
                    String reviewFile = resItem.CommentObj.ReviewFile;
                    resItem.CommentObj.ReviewFile = reviewFile.Substring(reviewFile.LastIndexOf("\\") + 1);
                    resItem.SourceOfItem = Common.DataObject.ResultItem.ITEM_SOURCE_NETWORK;
                }
            }
            ntwkDealer.sendSearchResult(arlResult, e);
        }
        
        /// <summary>
        /// handler of the DownloadRequestReceived event triggered from network dealer component
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void ntwkDealer_DownloadRequestReceived(object sender, Pbdms.NetworkDealer.EventArgs.DownloadRequestReceivedEventArgs e)
        {
            //check the file, if OK -> send result
            Pbdms.NetworkDealer.Requests.DownloadRequest drqObj = e.DownloadRequestObj;
            Common.DataObject.FileInfo fileInfoObj = DataController.FileInfoController.create().getFileInfoFromDB(drqObj.itemId);
            Common.DataObject.Comment commentObj = DataController.CommentController.create().getCommentFromDB(drqObj.itemId);

            String fileName = fileInfoObj.FileName;
            String filePath = fileInfoObj.Location + "\\" + fileInfoObj.FileName;

            if (System.IO.File.Exists(filePath ) || ( !commentObj.ReviewFile.Equals("") && System.IO.File.Exists(commentObj.ReviewFile)))
            {   
                
                //server sends a message to grant the request
                string msg = drqObj.itemId.ToString();
                if (System.IO.File.Exists(filePath ))
                {
                    msg += "," + fileInfoObj.Size.ToString() + "," + fileName;
                }
                if (!commentObj.ReviewFile.Equals("") && System.IO.File.Exists(commentObj.ReviewFile))
                {
                    System.IO.FileInfo fInfoReviewFile = new System.IO.FileInfo(commentObj.ReviewFile);
                    msg += "," + fInfoReviewFile.Length.ToString() + "," + fInfoReviewFile.Name;
                }
                ntwkDealer.sendDownloadResponse_Granted(msg, IPAddress.Parse(e.DownloadRequestObj.ipAddSource));
            }
            else
            {
                //if not OK, send a reject message.
                string msg = fileName;
                ntwkDealer.sendDownloadResponse_Rejected(msg,IPAddress.Parse(e.DownloadRequestObj.ipAddSource));
            }
        }

        void ntwkDealer_browseRequestReceived(object sender, Pbdms.NetworkDealer.EventArgs.BrowseRequestReceivedEventArgs e)
        {
            //send list of buddies
            String strBuddies="";
            System.Collections.ArrayList arlTemp = DataController.BuddyController.create().getListOfBuddies();
            if (arlTemp!=null && arlTemp.Count>0)
            {
                foreach (Common.DataObject.Buddy bdy in arlTemp)
                {
                    strBuddies += bdy.Name + " (" + bdy.IpAdd + ")*";
                }
                strBuddies = strBuddies.Substring(0,strBuddies.LastIndexOf("*"));
            }
            ntwkDealer.sendBrowseResultBuddy(strBuddies, e);

            //send list of result items:
            System.Collections.ArrayList arlResultItems = new System.Collections.ArrayList();
            System.Collections.ArrayList arlItemIds = DataController.ItemController.create().getListOfItemIDs();

            if (arlItemIds != null && arlItemIds.Count > 0)
            {
                for (int i = 0; i < arlItemIds.Count; i++)
                {
                    Common.DataObject.ResultItem r = new Pbdms.Common.DataObject.ResultItem();
                    r.ItemObj = DataController.ItemController.create().getItemFromDB((String)(arlItemIds[i]));
                    if (r.ItemObj.BPrivate == false)
                    {
                        Common.DataObject.Comment commentObj = DataController.CommentController.create().getCommentFromDB((String)(arlItemIds[i]));
                        commentObj.ReviewFile = commentObj.ReviewFile.Substring(commentObj.ReviewFile.LastIndexOf("\\")+1);
                        r.CommentObj = commentObj;
                        Common.DataObject.FileInfo fileInfoObj = DataController.FileInfoController.create().getFileInfoFromDB((String)(arlItemIds[i]));
                        fileInfoObj.Location = NetworkDealer.NetworkDealer.ipAddMyComputer.ToString();
                        r.FileInfoObj = fileInfoObj;
                        r.SourceOfItem = Common.DataObject.ResultItem.ITEM_SOURCE_NETWORK;
                        arlResultItems.Add(r);
                    }
                }
                if (arlResultItems.Count>0)
                    ntwkDealer.sendBrowseResultItems(arlResultItems, e);
            }
        }

        void ntwkDealer_browseResultBuddyReceived(object sender, Pbdms.NetworkDealer.EventArgs.BrowseResultBuddyReceivedEventArgs e)
        {
            processBuddyResultReceived(sender, e);
        }

        /// <summary>
        /// start listening on the network
        /// </summary>
        public void startListening()
        {
            ntwkDealer.startListening();
        }
        /// <summary>
        /// stop listening on the network
        /// </summary>
        public void stopListening()
        {
            ntwkDealer.stopListening();
        }

        
    }
}
